cls **resolve(cls *c){

}

void alloc(int i){
}


void check_target(expr_ty e, environment *env, environment *obj){
  expr_ty e, f;
  int i;
  switch(e->kind){
  case Attribute_kind:
    f = e->value;
    if(obj && f->kind == Name_kind && f->id == "self"){ //klaf bang self id
      obj = add_env(obj, e->v.Attribute.attr);
    }
    break;
  case Name_kind:
    obj = add_env(env, e->v.Name.id);
    break;
  case List_kind:
    for(i = 0 ; i < e->v.List.elts->size ; i++){
      check_target(e->v.List.elts->elements[i], env, obj);
    }
    break;
  case Tuple_kind
    for(i = 0 ; i < e->v.Tuple.elts->size ; i++){
      check_target(e->v.Tuple.elts->elements[i], env, obj);
    }
    break;
  }
}

void *compile_exp(expr_ty e, environment *env){
  int i, j;
  label l, l0, l1;
  switch(e->kind){
  case BoolOp_kind:
    compile_exp(e->v.BoolOp.values->elements[0], env);
    if(e->v.BoolOp.op == And){
      label ls[e->v.BoolOp.values->size-1];
      for(i = 1 ; i < e->v.BoolOp.values->size ; i++){
	cmp(eax, 0);
	ls[i-1] = je();
	compile_exp(e->v.BoolOp.values->elements[i], env);
      }
      i--;
      while(i){
	setlbl(ls[--i]);
      }
    }else{
      label ls[e->v.BoolOp.values->size-1];
      for(i = 1 ; i < e->v.BoolOp.values->size ; i++){
	cmp(eax, 0);
	ls[i-1] = jne();
	compile_exp(e->v.BoolOp.values->elements[i], env);
      }
      i--;
      while(i){
	setlbl(ls[--i]);
      }
    }
    break;
  case BinOp_kind:
    compile_exp(e->v.BinOp.left, env);
    push(eax);
    compile_exp(e->v.BinOp.right, env)
    pop(ebx);
    binop(e->v.BinOp.op);
    break;
  case UnaryOp_kind:
    compile_exp(e->v.UnaryOp.operand, env);
    unaryop(e->v.UnaryOp.op);
    break;
  case Lambda_kind:
    break;
  case Dict_kind:
    break;
  case ListComp_kind:
    l1 = getlbl();
    compile_exp(e->v.ListComp.generators->elements[0]->iter, env);
    compile_target(e->v.ListComp.generators->elements[0]->target, env);
    cmp(eax, 0);
    l = jeq();
    for(j = 0 ; j < e->v.ListComp.generators->elements[0]->ifs->size){
      compile_exp(e->v.ListComp.generators->elements[0]->ifs->elements[i], env);
      cmp(eax, 0);
      jeq(l1);
    }
    for(i = 1 ; i < e->v.ListComp.generators->size ; i++){
      l0 = l1;
      l1 = getlbl();
      compile_exp(e->v.ListComp.generators->elements[i]->iter, env);
      compile_target(e->v.ListComp.generators->elements[i]->target, env);
      cmp(eax, 0);
      jeq(l0);
      for(j = 0 ; j < e->v.ListComp.generators->elements[i]->ifs->size){
	compile_exp(e->v.ListComp.generators->elements[i]->ifs->elements[i], env);
	cmp(eax, 0);
	jeq(l1);
      }
    }
    compile_exp(elt, env);
    jmp(l1);
    setlbl(l);
    break;
  case GeneratorExp_kind:
    break;
  case Yield_kind:
    break;
  case Compare_kind:
    compile_exp(e->v.Compare.left);
    push(eax);
    {
      label ls[e->v.Compare.ops->size];
      for(i = 0 ; i < e->v.Compare.ops->size ; i++){
	compile_exp(e->v.Compare.comparators->elements[i], env);
	pop(ebx);
	cmp(aex, ebx);
	ls[i] = jcc(e->v.Compare.ops->elements[i]);
	push(eax);
      }
      alloc(2);
      mov(*(eax), booltype);
      mov(*(eax + 4), true);
      l = jmp();
      while(i){
	setlbl(ls[--i]);
      }
    }
    alloc(2);
    mov(*(eax), booltype);
    mov(*(eax + 4), false);
    setlbl(l);
    break;
  case Call_kind:
    compile_exp(e->v.Call.func, env);
    push(eax);
    for(i = 0 ; i < e->v.Call.args->size ; i++){
      compile_exp(e->v.Call.args->elements[i], env);
      push(eax);
    }
    push(e->v.Call.args->size); //klaf bang GC!!!
    mov(eax, esp + e->v.Call.args->size*4);
    mov(ebx, *eax);
    cmp(ebx, funtype);
    l = jne();
    call(*(eax + 4));
    setlbl(l);
    break;
  case Repr_kind:
    break;
  case Num_kind:
    alloc(2);
    mov(*(eax), inttype);
    mov(*(eax+4), PyInt_Value(e->v.Num.n));
    break;
  case Str_kind:
    alloc(2);
    mov(*(eax), stringtype);
    mov(*(eax+4), PyString_AsString(e->v.Str.s));
    break;
  case Attribute_kind:
    break;
  case Subscript_kind:
    break;
  case Name_kind:
    mov(eax, *(esp+arraylist_search(env, lookup(e->v.Name.id))));
    break;
  case List_kind:
    break;
  case Tuple_kind:
    for(i = 0 ; i < e->v.Tuple.elts->size ; i++){
      compile_exp(e->v.Tuple.elts->elements[i], env);
      push(eax);
    }
    alloc(1+e->v.Tuple.elts->size);
    mov(*(eax), tupletype);
    for(i = 0 ; i < e->v.Tuple.elts->size ; i++){
      pop(ebx);
      mov(*(eax+4+i), ebx);
    }
    break;
  }
}

void *compile_stmt(stmt_ty s, environment *env){
  int i, j;
  label l, l0, l1;
  switch(s->kind){
  case FunctionDef_kind:
    break;
  case ClassDef_kind:
    break;
  case Return_kind:
    while(fin){
    }
    add(esp, env->size);
    ret();
    break;
  case Delete_kind:
    break;
  case Assign_kind:
    break;
  case AugAssign_kind:
    break;
  case Print_kind:
    break;
  case For_kind:
    compile_exp(s->v.For.iter, env);
    l = getloc(); //continue
    compile_target(s->v.For.target, env);
    cmp(eax, 0);
    l0 = jeq();
    for(i = 0 ; i < s->v.For.body->size ; i++){
      compile_stmt(s->v.For.body->elements[i], env);
    }
    jmp(l);
    setlbl(l0);
    if(s->v.For.orelse){
      for(i = 0 ; i < s->v.While.orelse->size ; i++){
	compile_stmt(s->v.While.orelse->elements[i], env);
      }
    }
    setlbl(l1); //break
    break;
  case While_kind:
    l = getloc(); //continue
    compile_exp(s->v.While.test, env);
    cmp(eax, 0);
    l0 = jeq();
    for(i = 0 ; i < s->v.While.body->size ; i++){
      compile_stmt(s->v.While.body->elements[i], env);
    }
    jmp(l);
    setlbl(l0);
    if(s->v.While.orelse){
      for(i = 0 ; i < s->v.While.orelse->size ; i++){
	compile_stmt(s->v.While.orelse->elements[i], env);
      }
    }
    setlbl(l1); //break
    break;
  case If_kind:
    compile_exp(s->v.If.test, env);
    cmp(eax, 0);
    l0 = jeq();
    for(i = 0 ; i < s->v.If.body->size ; i++){
      compile_stmt(s->v.If.body->elements[i], env);
    }
    if(s->v.If.orelse){
      l1 = jmp();
      setlbl(l0);
      for(i = 0 ; i < s->v.If.orelse->size ; i++){
	compile_stmt(s->v.If.orelse->elements[i], env);
      }
      setlbl(l1);
    }else
      setlbl(l0);
    break;
  case Raise_kind:
    compile_exp(s->v.Raise.test, env); //klaf bang more
    mov(esp, ebp);
    pop(ebp);
    ret();
    break;
  case TryExcept_kind:
    l = push();
    push(ebp);
    mov(ebp, esp);
    for(i = 0 ; i < s->v.TryExcept.body->size ; i++){
      compile_stmt(s->v.TryExcept.body->elements[i], env);
    }
    mov(esp, ebp);
    pop(ebp);
    add(esp, 4);
    setlbl(l);
    {
      label ls[s->v.TryExcept.handlers->size];
      for(i = 0 ; i < s->v.TryExcept.handlers->size ; i++){
	compile_exp(s->v.TryExcept.handlers->elements[i]->type);
	//instance
	l = jcc();
	if(s->v.TryExcept.handlers->elements[i]->name)
	  compile_target(s->v.TryExcept.handlers->elements[i]->name, env);
	for(j = 0 ; j < s->v.TryExcept.handlers->elements[i]->body->size ; j++){
	  compile_stmt(v.TryExcept.handlers->elements[i]->body->elements[j], env);
	}
	ls[i] = jmp();
	setlbl(l);
      }
      if(s->v.TryExcept.orelse){
	for(i = 0 ; i < s->v.TryExcept.orelse->size ; i++){
	  compile_stmt(s->v.TryExcept.orelse->elements[i], env);
	}
      }
      while(i){
	setlbl(ls[--i]);
      }
    }
    break;
  case TryFinally_kind:
    l = push();
    push(ebp);
    mov(ebp, esp);
    for(i = 0 ; i < s->v.TryFinally.body->size ; i++){
      compile_stmt(s->v.TryFinally.body->elements[i], env); //cnt, brk
    }
    mov(esp, ebp);
    pop(ebp);
    add(esp, 4);
    mov(eax, 0); //klaf bang!!! survive!!!
    setlbl(l);
    for(i = 0 ; i < s->v.TryFinally.finalbody->size ; i++){
      compile_stmt(s->v.TryFinally.finalbody->elements[i], env);
    }
    cmp(eax, 0);
    l = jeq();
    mov(esp, ebp);
    pop(ebp);
    ret();
    setlbl(l);
    break;
  case Assert_kind:
    break;
  case Import_kind:
    break;
  case ImportFrom_kind:
    break;
  case Exec_kind:
    break;
  case Global_kind:
    break;
  case Expr_kind:
    compile_exp(s->v.Expr.value, env, obj);
    break;
  case Pass_kind:
    break;
  case Break_kind:
    while(fin < cnt){
    }
    jmp(brk);
    break;
  case Continue_kind:
    while(fin < cnt){
    }
    jmp(cnt);
    break;
  }
}

void *compile_fun(asdl_seq s, environment *env){
  int i;
  for(i = 0 ; i < s->size ; i++){
    compile_stmt(s->elements[i], env);
  }
}

void check_stmt(stmt_ty s, environment *env, environment *obj){
  int i;
  environment new_env, new_obj;
  switch(s->kind){
  case FunctionDef_kind:
    obj = add_env(env, s->v.FunctionDef.name);
    check_fun(s);
    break;
  case ClassDef_kind:
    obj = add_env(env, s->v.ClassDef.name); //gem new_env, new_obj
    check_cls();
    def_class(s, new_env, new_obj);
    break;
  case Assign_kind:
    for(i = 0 ; i < s->v.Assign.targets->size ; i++){
      check_target(s->v.Assign.targets->elements[i], env, obj);
    }
    break;
  case AugAssign_kind:
    check_target(s->v.AugAssign.target, env, obj);
    break;
  case For_kind:
    check_target(s->v.For.target, env, obj);
    for(i = 0; i < s->v.For.body->size; i++) {
      check_stmt(s->v.For.body->elements[i], env, obj);
    }
    for(i = 0; i < s->v.For.orelse->size; i++) {
      check_stmt(s->v.For.orelse->elements[i], env, obj);
    }
    break;
  case While_kind:
    for(i = 0; i < s->v.While.body->size; i++) {
      check_stmt(s->v.While.body->elements[i], env, obj);
    }
    for(i = 0; i < s->v.While.orelse->size; i++) {
      check_stmt(s->v.While.orelse->elements[i], env, obj);
    }
    break;
  case If_kind:
    for(i = 0; i < s->v.If.body->size; i++) {
      check_stmt(s->v.If.body->elements[i], env, obj);
    }
    for(i = 0; i < s->v.If.orelse->size; i++) {
      check_stmt(s->v.If.orelse->elements[i], env, obj);
    }
    break;
  case TryExcept_kind:
    for(i = 0 ; i < s->v.TryExcept.handlers->size ; i++){
      excepthandler_ty h = s->v.TryExcept.handlers->elements[i];
      check_target(h->name, env, obj);
    }
    break;
  case Expr_kind: //lambda
    break;
    /*
  case Import_kind:
    break;
  case ImportFrom_kind:
    break;
  case Exec_kind:
    break;
  case Global_kind:
    break;
    */
  }
}

void check_fun(){
  new_env = newEnv(); //save me!!!
  for(i = 0 ; i < s->v.FunctionDef.args->args->size ; i++){
    obj = add_env(new_env, s->v.FunctionDef.args->args->elements[i]->v.Name.id);
  }
  if(s->v.FunctionDef.args->vararg)
    obj = add_env(new_env, s->v.FunctionDef.args->vararg);
  if(s->v.FunctionDef.args->kwarg)
    obj = add_env(new_env, s->v.FunctionDef.args->kwarg);
  if(s->v.FunctionDef.args->args->size == 0 && s->v.FunctionDef.args->args->elements[i]->v.Name.id != "self")  //klaf bang self id
    obj = NULL;
  for(i = 0; i < s->v.FunctionDef.body->size; i++) {
    check_stmt(s->v.FunctionDef.body->elements[i], new_env, obj);
  }
  compile_fun(s->v.FunctionDef.body, environment *env, environment *obj);
}

void check_cls(){
  new_env = newEnv();
  new_obj = newEnv();
  for(i = 0; i < s->v.ClassDef.body->size; i++) {
    check_stmt(s->v.ClassDef.body->elements[i], new_env, new_obj);
  }
}

void *compile(mod_ty m){
  int i;
  switch(m->kind){
  case Module_kind:
    for(i = 0 ; i < m->v.Module.body->size ; i++){
      stmt_ty s = m->v.Module.body->elements[i];
      check_stmt(s, , );
    }
    break;
  case Interactive_kind:
    for(i = 0 ; i < m->v.Interactive.body->size ; i++){
      stmt_ty s = m->v.Interactive.body->elements[i];
      check_stmt(s, , );
    }
    break;
  case Expression_kind: //lambda
    break;
  case Suite_kind:
    for(i = 0 ; i < m->v.Suite.body->size ; i++){
      stmt_ty s = m->v.Suite.body->elements[i];
      check_stmt(s, , );
    }
    break;
  }
}



if elif else, while else, for in else, try except else finally, with, def, class, @
del pass break continue return raise yield
import global exec assert

augassign: ('+=' | '-=' | '*=' | '/=' | '%=' | '&=' | '|=' | '^=' |
            '<<=' | '>>=' | '**=' | '//=')
  if else   or, and, not                     lambda
comp_op: '<'|'>'|'=='|'>='|'<='|'<>'|'!='|'in'|'not' 'in'|'is'|'is' 'not
|^& << >> +- */%// +-~ ** 


  switch(m->kind){
  case Module_kind:
    break;
  case Interactive_kind:
    break;
  case Expression_kind:
    break;
  case Suite_kind:
    break;
  }
  switch(s->kind){
  case FunctionDef_kind:
    break;
  case ClassDef_kind:
    break;
  case Return_kind:
    break;
  case Delete_kind:
    break;
  case Assign_kind:
    break;
  case AugAssign_kind:
    break;
  case Print_kind:
    break;
  case For_kind:
    break;
  case While_kind:
    break;
  case If_kind:
    break;
  case Raise_kind:
    break;
  case TryExcept_kind:
    break;
  case TryFinally_kind:
    break;
  case Assert_kind:
    break;
  case Import_kind:
    break;
  case ImportFrom_kind:
    break;
  case Exec_kind:
    break;
  case Global_kind:
    break;
  case Expr_kind:
    break;
  case Pass_kind:
    break;
  case Break_kind:
    break;
  case Continue_kind:
    break;
  }
  switch(e->kind){
  case BoolOp_kind:
    break;
  case BinOp_kind:
    break;
  case UnaryOp_kind:
    break;
  case Lambda_kind:
    break;
  case Dict_kind:
    break;
  case ListComp_kind:
    break;
  case GeneratorExp_kind:
    break;
  case Yield_kind:
    break;
  case Compare_kind:
    break;
  case Call_kind:
    break;
  case Repr_kind:
    break;
  case Num_kind:
    break;
  case Str_kind:
    break;
  case Attribute_kind:
    break;
  case Subscript_kind:
    break;
  case Name_kind:
    break;
  case List_kind:
    break;
  case Tuple_kind
    break;
  }
